package com.example.excel_db.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.example.excel_db.dto.ExcelTemplateDTO;
import com.example.excel_db.dto.ExcelTemplateFieldDTO;
import com.example.excel_db.entity.ExcelTemplate;
import com.example.excel_db.entity.ExcelTemplateField;
import com.example.excel_db.repository.ExcelTemplateFieldRepository;
import com.example.excel_db.repository.ExcelTemplateRepository;
import com.example.excel_db.service.ExcelTemplateService;
import com.example.excel_db.validator.ExcelDataValidatorFactory;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Excel模板服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ExcelTemplateServiceImpl implements ExcelTemplateService {

    private final ExcelTemplateRepository templateRepository;
    private final ExcelTemplateFieldRepository fieldRepository;
    private final ExcelDataValidatorFactory validatorFactory;

    @Value("${file.upload.path}")
    private String uploadPath;

    @Override
    @Transactional
    public ExcelTemplateDTO createTemplate(ExcelTemplateDTO templateDTO) {
        // 检查模板名称是否已存在
        if (templateRepository.existsByName(templateDTO.getName())) {
            throw new IllegalArgumentException("模板名称已存在: " + templateDTO.getName());
        }

        // 创建模板实体
        ExcelTemplate template = new ExcelTemplate();
        template.setName(templateDTO.getName());
        template.setDescription(templateDTO.getDescription());
        template = templateRepository.save(template);

        // 保存模板字段
        if (templateDTO.getFields() != null && !templateDTO.getFields().isEmpty()) {
            List<ExcelTemplateField> fields = new ArrayList<>();
            for (ExcelTemplateFieldDTO fieldDTO : templateDTO.getFields()) {
                ExcelTemplateField field = new ExcelTemplateField();
                BeanUtils.copyProperties(fieldDTO, field);
                field.setTemplate(template);
                fields.add(field);
            }
            fieldRepository.saveAll(fields);
            template.setFields(fields);
        }

        return convertToDTO(template);
    }

    @Override
    @Transactional
    public ExcelTemplateDTO updateTemplate(ExcelTemplateDTO templateDTO) {
        // 检查模板是否存在
        ExcelTemplate template = templateRepository.findById(templateDTO.getId())
                .orElseThrow(() -> new EntityNotFoundException("模板不存在: " + templateDTO.getId()));

        // 检查模板名称是否已被其他模板使用
        if (!template.getName().equals(templateDTO.getName()) && 
                templateRepository.existsByName(templateDTO.getName())) {
            throw new IllegalArgumentException("模板名称已存在: " + templateDTO.getName());
        }

        // 更新模板基本信息
        template.setName(templateDTO.getName());
        template.setDescription(templateDTO.getDescription());
        template = templateRepository.save(template);

        // 清除校验器缓存
        validatorFactory.clearCache(template.getId());

        return convertToDTO(template);
    }

    @Override
    @Transactional
    public void deleteTemplate(Long id) {
        // 检查模板是否存在
        ExcelTemplate template = templateRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("模板不存在: " + id));

        // 删除模板文件
        if (StringUtils.hasText(template.getFilePath())) {
            try {
                Files.deleteIfExists(Paths.get(template.getFilePath()));
            } catch (IOException e) {
                log.error("删除模板文件失败: {}", template.getFilePath(), e);
            }
        }

        // 删除模板及关联字段
        templateRepository.delete(template);

        // 清除校验器缓存
        validatorFactory.clearCache(id);
    }

    @Override
    public ExcelTemplateDTO getTemplateById(Long id) {
        ExcelTemplate template = templateRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("模板不存在: " + id));
        return convertToDTO(template);
    }

    @Override
    public ExcelTemplateDTO getTemplateByName(String name) {
        ExcelTemplate template = templateRepository.findByName(name)
                .orElseThrow(() -> new EntityNotFoundException("模板不存在: " + name));
        return convertToDTO(template);
    }

    @Override
    public List<ExcelTemplateDTO> getAllTemplates() {
        List<ExcelTemplate> templates = templateRepository.findAll();
        return templates.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    @Override
    public Page<ExcelTemplateDTO> getTemplates(Pageable pageable) {
        Page<ExcelTemplate> templates = templateRepository.findAll(pageable);
        return templates.map(this::convertToDTO);
    }

    @Override
    @Transactional
    public ExcelTemplateFieldDTO addTemplateField(Long templateId, ExcelTemplateFieldDTO fieldDTO) {
        // 检查模板是否存在
        ExcelTemplate template = templateRepository.findById(templateId)
                .orElseThrow(() -> new EntityNotFoundException("模板不存在: " + templateId));

        // 创建字段实体
        ExcelTemplateField field = new ExcelTemplateField();
        BeanUtils.copyProperties(fieldDTO, field);
        field.setTemplate(template);
        field = fieldRepository.save(field);

        // 清除校验器缓存
        validatorFactory.clearCache(templateId);

        // 转换为DTO返回
        ExcelTemplateFieldDTO resultDTO = new ExcelTemplateFieldDTO();
        BeanUtils.copyProperties(field, resultDTO);
        resultDTO.setTemplateId(templateId);
        return resultDTO;
    }

    @Override
    @Transactional
    public ExcelTemplateFieldDTO updateTemplateField(ExcelTemplateFieldDTO fieldDTO) {
        // 检查字段是否存在
        ExcelTemplateField field = fieldRepository.findById(fieldDTO.getId())
                .orElseThrow(() -> new EntityNotFoundException("字段不存在: " + fieldDTO.getId()));

        // 更新字段信息
        field.setFieldName(fieldDTO.getFieldName());
        field.setFieldColumn(fieldDTO.getFieldColumn());
        field.setFieldType(fieldDTO.getFieldType());
        field.setRequired(fieldDTO.isRequired());
        field.setValidator(fieldDTO.getValidator());
        field.setOrderNum(fieldDTO.getOrderNum());
        field = fieldRepository.save(field);

        // 清除校验器缓存
        validatorFactory.clearCache(field.getTemplate().getId());

        // 转换为DTO返回
        ExcelTemplateFieldDTO resultDTO = new ExcelTemplateFieldDTO();
        BeanUtils.copyProperties(field, resultDTO);
        resultDTO.setTemplateId(field.getTemplate().getId());
        return resultDTO;
    }

    @Override
    @Transactional
    public void deleteTemplateField(Long fieldId) {
        // 检查字段是否存在
        ExcelTemplateField field = fieldRepository.findById(fieldId)
                .orElseThrow(() -> new EntityNotFoundException("字段不存在: " + fieldId));

        Long templateId = field.getTemplate().getId();

        // 删除字段
        fieldRepository.delete(field);

        // 清除校验器缓存
        validatorFactory.clearCache(templateId);
    }

    @Override
    public List<ExcelTemplateFieldDTO> getTemplateFields(Long templateId) {
        // 检查模板是否存在
        if (!templateRepository.existsById(templateId)) {
            throw new EntityNotFoundException("模板不存在: " + templateId);
        }

        // 查询字段列表
        List<ExcelTemplateField> fields = fieldRepository.findByTemplateIdOrderByOrderNumAsc(templateId);
        return fields.stream()
                .map(field -> {
                    ExcelTemplateFieldDTO dto = new ExcelTemplateFieldDTO();
                    BeanUtils.copyProperties(field, dto);
                    dto.setTemplateId(templateId);
                    return dto;
                })
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public ExcelTemplateDTO uploadTemplateFile(Long templateId, MultipartFile file) {
        // 检查模板是否存在
        ExcelTemplate template = templateRepository.findById(templateId)
                .orElseThrow(() -> new EntityNotFoundException("模板不存在: " + templateId));

        // 创建上传目录
        File uploadDir = new File(uploadPath);
        if (!uploadDir.exists() && !uploadDir.mkdirs()) {
            throw new RuntimeException("无法创建上传目录: " + uploadPath);
        }

        // 保存文件
        String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
        Path filePath = Paths.get(uploadPath, fileName);
        try {
            Files.copy(file.getInputStream(), filePath);
        } catch (IOException e) {
            throw new RuntimeException("保存模板文件失败", e);
        }

        // 删除旧文件
        if (StringUtils.hasText(template.getFilePath())) {
            try {
                Files.deleteIfExists(Paths.get(template.getFilePath()));
            } catch (IOException e) {
                log.error("删除旧模板文件失败: {}", template.getFilePath(), e);
            }
        }

        // 更新模板文件路径
        template.setFilePath(filePath.toString());
        template = templateRepository.save(template);

        return convertToDTO(template);
    }

    @Override
    public byte[] downloadTemplateFile(Long templateId) {
        // 检查模板是否存在
        ExcelTemplate template = templateRepository.findById(templateId)
                .orElseThrow(() -> new EntityNotFoundException("模板不存在: " + templateId));

        // 检查模板文件是否存在
        if (!StringUtils.hasText(template.getFilePath())) {
            // 如果模板文件不存在，生成空白模板
            return generateEmptyTemplateFile(templateId);
        }

        // 读取模板文件
        try {
            return Files.readAllBytes(Paths.get(template.getFilePath()));
        } catch (IOException e) {
            throw new RuntimeException("读取模板文件失败", e);
        }
    }

    @Override
    public byte[] generateEmptyTemplateFile(Long templateId) {
        // 检查模板是否存在
        ExcelTemplate template = templateRepository.findById(templateId)
                .orElseThrow(() -> new EntityNotFoundException("模板不存在: " + templateId));

        // 查询模板字段
        List<ExcelTemplateField> fields = fieldRepository.findByTemplateOrderByOrderNumAsc(template);
        if (fields.isEmpty()) {
            throw new IllegalStateException("模板没有定义字段");
        }

        // 准备表头数据
        List<List<String>> headList = new ArrayList<>();
        for (ExcelTemplateField field : fields) {
            List<String> head = new ArrayList<>();
            head.add(field.getFieldColumn() + (field.isRequired() ? "（必填）" : ""));
            headList.add(head);
        }

        // 设置表头和内容样式
        WriteCellStyle headStyle = new WriteCellStyle();
        headStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        WriteFont headFont = new WriteFont();
        headFont.setBold(true);
        headFont.setFontHeightInPoints((short) 12);
        headStyle.setWriteFont(headFont);
        headStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        headStyle.setVerticalAlignment(VerticalAlignment.CENTER);

        WriteCellStyle contentStyle = new WriteCellStyle();
        contentStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        contentStyle.setVerticalAlignment(VerticalAlignment.CENTER);

        HorizontalCellStyleStrategy styleStrategy = new HorizontalCellStyleStrategy(headStyle, contentStyle);

        // 生成Excel文件
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        EasyExcel.write(outputStream)
                .head(headList)
                .registerWriteHandler(styleStrategy)
                .sheet(template.getName())
                .doWrite(Collections.emptyList());

        return outputStream.toByteArray();
    }

    @Override
    public ExcelTemplateDTO convertToDTO(ExcelTemplate template) {
        if (template == null) {
            return null;
        }

        ExcelTemplateDTO dto = new ExcelTemplateDTO();
        BeanUtils.copyProperties(template, dto);

        // 转换字段列表
        if (template.getFields() != null && !template.getFields().isEmpty()) {
            List<ExcelTemplateFieldDTO> fieldDTOs = template.getFields().stream()
                    .map(field -> {
                        ExcelTemplateFieldDTO fieldDTO = new ExcelTemplateFieldDTO();
                        BeanUtils.copyProperties(field, fieldDTO);
                        fieldDTO.setTemplateId(template.getId());
                        return fieldDTO;
                    })
                    .collect(Collectors.toList());
            dto.setFields(fieldDTOs);
        }

        return dto;
    }
}